﻿using nfrastructure.Utility.Core.RabbitMq.Providers;
using RabbitMQ.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Infrastructure.Utility.Core.RabbitMq.Providers
{

    public class Publisher : IPublisher
    {

        private readonly IProvider _mqProvider;
        private readonly IConnection connection;

        private Publisher()
        {

        }

        public Publisher(IProvider mqprovider)
        {
            _mqProvider = mqprovider;
            connection = mqprovider.CreateConnectionInPool();
        }

        public bool Publish<T>(string routeKey, T message) where T : class
        {
            return Publish(routeKey, nameof(message), message);
        }

        public bool Publish<T>(string routeKey, string fullName, T message, IDictionary<string, string> headers = null) where T : class
        {
            try
            {
                using (var channel = this._mqProvider.CreateChannel(connection))
                {
                    channel.ExchangeDeclare(this._mqProvider.ExchangeName,
                        ExchangeType.Topic,
                        durable: this._mqProvider.Durable);
                    var content = this._mqProvider.ToJson(message);
                    var bytes = Encoding.UTF8.GetBytes(content);
                    IBasicProperties properties = null;

                    if (headers == null)
                    {
                        headers = new Dictionary<string, string>();
                    }
                    var messageId = SnowflakeId.Default().NextId().ToString();
                    headers.Add(Headers.MessageId, messageId);
                    headers.Add(Headers.MessageName, routeKey);
                    headers.Add(Headers.Type, fullName);
                    headers.Add(Headers.SentTime, DateTimeOffset.Now.ToString());
                    if (!headers.ContainsKey(Headers.CorrelationId))
                    {
                        headers.Add(Headers.CorrelationId, messageId);
                        headers.Add(Headers.CorrelationSequence, 0.ToString());
                    }

                    if (this._mqProvider.Durable)
                    {
                        properties = channel.CreateBasicProperties();
                        properties.DeliveryMode = 2;
                        properties.Headers = headers.ToDictionary(x => x.Key, x => (object)x.Value);
                    }
                    channel.BasicPublish(
                        exchange: this._mqProvider.ExchangeName,
                        routingKey: routeKey,
                        basicProperties: properties,
                        body: bytes);
                }
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
            finally
            {
                this._mqProvider.ResetConnectionToFree(connection);
            }
        }
    }
}
